import PartnerContentLink from '@/components/PartnerContentLink';
import Callout from '@/components/Callout';
import {Tabs} from 'nextra/components';
import Details from '@/components/Details';
import {CourseVideoBanner} from '@/components/CourseBanner';

# Request configuration

Configuration properties that you use across your Next.js app can be set per request.

## Server & Client Components [#server-client-components]

Depending on if you handle internationalization in [Server- or Client Components](/docs/environments/server-client-components), the configuration from `i18n/request.ts` or `NextIntlClientProvider` will be applied respectively.

### `i18n/request.ts` & `getRequestConfig` [#i18n-request]

`i18n/request.ts` can be used to provide configuration for **server-only** code, i.e. Server Components, Server Actions & friends. The configuration is provided via the `getRequestConfig` function and provides a `requestLocale` parameter in case you're using [locale-based routing](/docs/routing).

```tsx filename="i18n/request.ts"
import {getRequestConfig} from 'next-intl/server';
import {routing} from '@/i18n/routing';

export default getRequestConfig(async ({requestLocale}) => {
  // ...

  return {
    locale,
    messages
    // ...
  };
});
```

The configuration object is created once for each request by internally using React's [`cache`](https://react.dev/reference/react/cache). The first component to use internationalization will call the function defined with `getRequestConfig`.

Since this function is executed during the Server Components render pass, you can call functions like [`cookies()`](https://nextjs.org/docs/app/api-reference/functions/cookies) and [`headers()`](https://nextjs.org/docs/app/api-reference/functions/headers) to return configuration that is request-specific.

### `NextIntlClientProvider`

`NextIntlClientProvider` can be used to provide configuration for **Client Components**.

```tsx filename="layout.tsx" /NextIntlClientProvider/
import {NextIntlClientProvider} from 'next-intl';
import {getMessages} from 'next-intl/server';

export default async function RootLayout(/* ... */) {
  // ...

  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider>...</NextIntlClientProvider>
      </body>
    </html>
  );
}
```

These props are inherited if you're rendering `NextIntlClientProvider` from a Server Component:

1. `locale`
2. `messages`
3. `now`
4. `timeZone`
5. `formats`

If you don't want to inherit some of these props, e.g. because you're selective about how you use internationalization in [Server & Client Components](/docs/environments/server-client-components), you can opt-out:

```tsx filename="layout.tsx"
<NextIntlClientProvider
  // Don't pass any messages to the client
  messages={null}
  // ...
>
  ...
</NextIntlClientProvider>
```

Additionally, nested instances of `NextIntlClientProvider` will inherit configuration from their respective ancestors. Note however that individual props are treated as atomic, therefore e.g. `messages` need to be merged manually—if necessary.

In contrast, these props are not inherited:

1. `onError`
2. `getMessageFallback`

<Details id="nextintlclientprovider-non-serializable-props">
<summary>How can I provide non-serializable props like `onError` to `NextIntlClientProvider`?</summary>

React limits the types of props that can be passed to Client Components to the ones that are [serializable](https://react.dev/reference/rsc/use-client#serializable-types). Since `onError` and `getMessageFallback` can receive functions, these configuration options can't be automatically inherited by the client side.

In order to define these values on the client side, you can add a provider that defines these props:

```tsx filename="IntlErrorHandlingProvider.tsx"
'use client';

import {NextIntlClientProvider} from 'next-intl';

export default function IntlErrorHandlingProvider({children}) {
  return (
    <NextIntlClientProvider
      onError={(error) => console.error(error)}
      getMessageFallback={({namespace, key}) => `${namespace}.${key}`}
    >
      {children}
    </NextIntlClientProvider>
  );
}
```

Once you have defined your client-side provider component, you can use it in a Server Component:

```tsx filename="layout.tsx"
import {NextIntlClientProvider} from 'next-intl';
import {getLocale} from 'next-intl/server';
import IntlErrorHandlingProvider from './IntlErrorHandlingProvider';

export default async function RootLayout({children}) {
  const locale = await getLocale();

  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider>
          <IntlErrorHandlingProvider>{children}</IntlErrorHandlingProvider>
        </NextIntlClientProvider>
      </body>
    </html>
  );
}
```

By doing this, your provider component will already be part of the client-side bundle and can therefore define and pass functions as props.

Note that the inner `NextIntlClientProvider` inherits the configuration from the outer one, only the `onError` and `getMessageFallback` functions are added.

</Details>

## Locale

The `locale` represents an identifier that contains the language and formatting preferences of users, optionally including regional information (e.g. `en-US`). Locales are specified as [IETF BCP 47 language tags](https://en.wikipedia.org/wiki/IETF_language_tag).

<Tabs items={['i18n/request.ts', 'Provider']}>
<Tabs.Tab>

Depending on if you're using [locale-based routing](/docs/routing), you can read the locale from the `requestLocale` parameter or provide a value on your own:

**With locale-based routing:**

```tsx filename="i18n/request.ts"
export default getRequestConfig(async ({requestLocale}) => {
  // Typically corresponds to the `[locale]` segment
  const requested = await requestLocale;
  const locale = hasLocale(routing.locales, requested)
    ? requested
    : routing.defaultLocale;

  return {
    locale
    // ...
  };
});
```

**Without locale-based routing:**

```tsx filename="i18n/request.ts"
export default getRequestConfig(async () => {
  // Provide a static locale, fetch a user setting,
  // read from `cookies()`, `headers()`, etc.
  const locale = 'en';

  return {
    locale
    // ...
  };
});
```

<Details id="server-request-locale">
<summary>Which values can the `requestLocale` parameter hold?</summary>

While the `requestLocale` parameter typically corresponds to the `[locale]` segment that was matched by the middleware, there are three special cases to consider:

1. **Overrides**: When an explicit `locale` is passed to [awaitable functions](/docs/environments/actions-metadata-route-handlers) like `getTranslations({locale: 'en'})`, then this value will be used instead of the segment.
1. **`undefined`**: The value can be `undefined` when a page outside of the `[locale]` segment renders (e.g. a language selection page at `app/page.tsx`).
1. **Invalid values**: Since the `[locale]` segment effectively acts like a catch-all for unknown routes (e.g. `/unknown.txt`), invalid values should be replaced with a valid locale. In addition to this, you might want to call `notFound()` in the [root layout](/docs/routing/setup#layout) to abort the render in this case.

</Details>

</Tabs.Tab>
<Tabs.Tab>

```tsx
<NextIntlClientProvider locale="en">...</NextIntlClientProvider>
```

</Tabs.Tab>
</Tabs>

<Details id="locale-change">
<summary>How can I change the locale?</summary>

Depending on if you're using [locale-based routing](/docs/routing), the locale can be changed as follows:

1. **With locale-based routing**: The locale is managed by the router and can be changed by using navigation APIs from `next-intl` like [`Link`](/docs/routing/navigation#link) or [`useRouter`](/docs/routing/navigation#userouter).
2. **Without locale-based routing**: You can change the locale by updating the value where the locale is read from (e.g. a cookie, a user setting, etc.).

Learn more:

<CourseVideoBanner
  className="mt-2"
  href="https://learn.next-intl.dev/chapters/04-adding-locales/02-locale-switcher"
  title="Locale switcher"
/>

</Details>

### `useLocale` & `getLocale` [#use-locale]

The current locale of your app is automatically incorporated into hooks like `useTranslations` & `useFormatter` and will affect the rendered output.

In case you need to use this value in other places of your app, e.g. to implement a locale switcher or to pass it to API calls, you can read it via `useLocale` or `getLocale`:

```tsx
// Regular components
import {useLocale} from 'next-intl';
const locale = useLocale();

// Async Server Components
import {getLocale} from 'next-intl/server';
const locale = await getLocale();
```

<Details id="locale-return-value">
<summary>Which value is returned from `useLocale`?</summary>

Depending on how a component renders, the returned locale corresponds to:

1. **Server Components**: The locale represents the value returned in [`i18n/request.ts`](#i18n-request).
2. **Client Components**: The locale is received from [`NextIntlClientProvider`](#nextintlclientprovider).

Note that `NextIntlClientProvider` automatically inherits the locale if it is rendered by a Server Component, therefore you rarely need to pass a locale to `NextIntlClientProvider` yourself.

</Details>

<Details id="locale-pages-router">
<summary>I'm using the Pages Router, how can I access the locale?</summary>

If you use [internationalized routing with the Pages Router](https://nextjs.org/docs/pages/building-your-application/routing/internationalization), you can receive the locale from the router in order to pass it to `NextIntlClientProvider`:

```tsx filename="_app.tsx"
import {useRouter} from 'next/router';

// ...

const router = useRouter();

return (
  <NextIntlClientProvider locale={router.locale}>
    ...
  </NextIntlClientProvider>;
);
```

</Details>

### `Locale` type [#locale-type]

When passing a `locale` to another function, you can use the `Locale` type for the receiving parameter:

```tsx
import {Locale} from 'next-intl';

async function getPosts(locale: Locale) {
  // ...
}
```

This can be helpful when integrating with backend services or a CMS:

<CourseVideoBanner
  className="mt-2"
  href="https://learn.next-intl.dev/chapters/07-content/01-overview"
  title="Backend content"
/>

<Callout>
  By default, `Locale` is typed as `string`. However, you can optionally provide
  a strict union based on your supported locales for this type by [augmenting
  the `Locale` type](/docs/workflows/typescript#locale).
</Callout>

## Messages

The most crucial aspect of internationalization is providing labels based on the user's language. The recommended workflow is to store your messages in your repository along with the code.

```
├── messages
│   ├── en.json
│   ├── de-AT.json
│   └── ...
...
```

Colocating your messages with app code is beneficial because it allows developers to make changes quickly and additionally, you can use the shape of your local messages for [type checking](/docs/workflows/typescript#messages).

If your team ships frequently, you can consider automating the translation process:

<CourseVideoBanner
  className="mt-2"
  href="https://learn.next-intl.dev/chapters/10-continuous-localization/01-local-workflow"
  title="AI translations with Crowdin"
/>

That being said, `next-intl` is agnostic to how you store messages and allows you to freely define an async function that fetches them while your app renders:

<Tabs items={['i18n/request.ts', 'Provider']}>
<Tabs.Tab>

```tsx filename="i18n/request.ts"
import {getRequestConfig} from 'next-intl/server';

export default getRequestConfig(async () => {
  return {
    messages: (await import(`../../messages/${locale}.json`)).default
    // ...
  };
});
```

After messages are configured, they can be used via [`useTranslations`](/docs/usage/translations#rendering-messages-with-usetranslations).

Since `getRequestConfig` can execute arbitrary code, you can also:

- Share messages across multiple locales
- Merge messages from another locale as fallbacks
- Load messages from a remote source

**Learn more:**

<CourseVideoBanner
  className="mt-2"
  href="https://learn.next-intl.dev/chapters/04-adding-locales/01-messages"
  title="Providing messages"
/>

<Details id="messages-split-files">
<summary>How can I split my messages into multiple files?</summary>

Since messages can be freely defined and loaded, you can split them into multiple files and merge them later at runtime if you prefer:

```tsx
const messages = {
  ...(await import(`../../messages/${locale}/login.json`)).default,
  ...(await import(`../../messages/${locale}/dashboard.json`)).default
};
```

Note that the [VSCode integration](/docs/workflows/vscode-integration) for `next-intl` can help you manage messages within a single, large file. If you're splitting messages purely for organizational reasons, you might want to consider using this instead.

</Details>

### `useMessages` & `getMessages` [#use-messages]

In case you require access to messages in a component, you can read them via `useMessages()` or `getMessages()` from your configuration:

```tsx
// Regular components
import {useMessages} from 'next-intl';
const messages = useMessages();

// Async Server Components
import {getMessages} from 'next-intl/server';
const messages = await getMessages();
```

</Tabs.Tab>
<Tabs.Tab>

```tsx
import {NextIntlClientProvider} from 'next-intl';
import {getMessages} from 'next-intl/server';
import pick from 'lodash/pick';

async function Component({children}) {
  // Read messages configured via `i18n/request.ts`
  const messages = await getMessages();

  return (
    <NextIntlClientProvider messages={pick(messages, ['Navigation'])}>
      ...
    </NextIntlClientProvider>
  );
}
```

</Tabs.Tab>
</Tabs>

## Time zone

Specifying a time zone affects the rendering of dates and times. By default, the time zone of the server runtime will be used, but can be customized as necessary.

<Tabs items={['i18n/request.ts', 'Provider']}>
<Tabs.Tab>

```tsx filename="i18n/request.ts"
import {getRequestConfig} from 'next-intl/server';

export default getRequestConfig(async () => {
  return {
    // The time zone can either be statically defined, read from the
    // user profile if you store such a setting, or based on dynamic
    // request information like the locale or a cookie.
    timeZone: 'Europe/Vienna'

    // ...
  };
});
```

</Tabs.Tab>
<Tabs.Tab>

```tsx
// The time zone can either be statically defined, read from the
// user profile if you store such a setting, or based on dynamic
// request information like the locale or a cookie.
const timeZone = 'Europe/Vienna';

<NextIntlClientProvider timeZone={timeZone}>...<NextIntlClientProvider>
```

</Tabs.Tab>
</Tabs>

The available time zone names can be looked up in the [tz database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).

The time zone in Client Components is automatically inherited from the server side if you wrap the relevant components in a `NextIntlClientProvider` that is rendered by a Server Component. For all other cases, you can specify the value explicitly on a wrapping `NextIntlClientProvider`.

**Learn more:**

<CourseVideoBanner
  className="mt-2"
  href="https://learn.next-intl.dev/chapters/05-formatting/02-dates-timezones"
  title="Dates & time zones"
/>

### `useTimeZone` & `getTimeZone` [#use-time-zone]

The configured time zone can be read via `useTimeZone` or `getTimeZone` in components:

```tsx
// Regular components
import {useTimeZone} from 'next-intl';
const timeZone = useTimeZone();

// Async Server Components
import {getTimeZone} from 'next-intl/server';
const timeZone = await getTimeZone();
```

## Now value [#now]

When formatting [relative dates and times](/docs/usage/dates-times#relative-times), `next-intl` will format times in relation to a reference point in time that is referred to as "now". While it can be beneficial in terms of caching to [provide this value](/docs/usage/dates-times#relative-times-usenow) where necessary, you can provide a global value for `now`, e.g. to ensure consistency when running tests.

<Tabs items={['i18n/request.ts', 'Provider']}>
<Tabs.Tab>

```tsx filename="i18n/request.ts"
import {getRequestConfig} from 'next-intl/server';

export default getRequestConfig(async () => {
  return {
    now: new Date('2024-11-14T10:36:01.516Z')

    // ...
  };
});
```

</Tabs.Tab>
<Tabs.Tab>

```tsx
const now = new Date('2024-11-14T10:36:01.516Z');

<NextIntlClientProvider now={now}>...</NextIntlClientProvider>;
```

</Tabs.Tab>
</Tabs>

If a `now` value is provided in `i18n/request.ts`, this will automatically be inherited by Client Components if you wrap them in a `NextIntlClientProvider` that is rendered by a Server Component.

### `useNow` & `getNow` [#use-now]

The configured `now` value can be read in components via `useNow` or `getNow`:

```tsx
// Regular components
import {useNow} from 'next-intl';
const now = useNow();

// Async Server Components
import {getNow} from 'next-intl/server';
const now = await getNow();
```

Note that the returned value defaults to the current date and time, therefore making this hook useful when [providing `now`](/docs/usage/dates-times#relative-times-usenow) for `format.relativeTime` even when you haven't configured a global `now` value.

## Formats

Prefer to watch a video?

<CourseVideoBanner
  className="mt-2"
  href="https://learn.next-intl.dev/chapters/05-formatting/04-global-formats"
  title="Global formats"
/>

To achieve consistent date, time, number and list formatting, you can define a set of global formats.

<Tabs items={['i18n/request.ts', 'Provider']}>
<Tabs.Tab>

```tsx filename="i18n/request.ts"
import {getRequestConfig} from 'next-intl/server';

export default getRequestConfig(async () => {
  return {
    formats: {
      dateTime: {
        short: {
          day: 'numeric',
          month: 'short',
          year: 'numeric'
        }
      },
      number: {
        precise: {
          maximumFractionDigits: 5
        }
      },
      list: {
        enumeration: {
          style: 'long',
          type: 'conjunction'
        }
      }
    }

    // ...
  };
});
```

</Tabs.Tab>
<Tabs.Tab>

```tsx
<NextIntlClientProvider
  formats={{
    dateTime: {
      short: {
        day: 'numeric',
        month: 'short',
        year: 'numeric'
      }
    },
    number: {
      precise: {
        maximumFractionDigits: 5
      }
    },
    list: {
      enumeration: {
        style: 'long',
        type: 'conjunction'
      }
    }
  }}
>
  ...
</NextIntlClientProvider>
```

</Tabs.Tab>
</Tabs>

Once you have `formats` set up, you can use them in your components via `useFormatter`:

```tsx
import {useFormatter} from 'next-intl';

function Component() {
  const format = useFormatter();

  format.dateTime(new Date('2020-11-20T10:36:01.516Z'), 'short');
  format.number(47.414329182, 'precise');
  format.list(['HTML', 'CSS', 'JavaScript'], 'enumeration');
}
```

<Callout>
  By default, format names are loosely typed as `string`. However, you can
  optionally use strict types by [augmenting the `Formats`
  type](/docs/workflows/typescript#formats).
</Callout>

Global formats for numbers, dates and times can be referenced in messages too:

```json filename="en.json"
{
  "ordered": "You've ordered this product on {orderDate, date, short}",
  "latitude": "Latitude: {latitude, number, precise}"
}
```

```tsx
import {useTranslations} from 'next-intl';

function Component() {
  const t = useTranslations();

  t('ordered', {orderDate: new Date('2020-11-20T10:36:01.516Z')});
  t('latitude', {latitude: 47.414329182});
}
```

Formats are automatically inherited from the server side if you wrap the relevant components in a `NextIntlClientProvider` that is rendered by a Server Component.

## Error handling (`onError` & `getMessageFallback`) [#error-handling]

By default, when a message fails to resolve or when the formatting failed, an error will be printed on the console. In this case `${namespace}.${key}` will be rendered instead to keep your app running.

This behavior can be customized with the `onError` and `getMessageFallback` configuration option.

<Tabs items={['i18n/request.ts', 'Provider']}>
<Tabs.Tab>

```tsx filename="i18n/request.ts"
import {getRequestConfig} from 'next-intl/server';
import {IntlErrorCode} from 'next-intl';

export default getRequestConfig(async () => {
  return {
    onError(error) {
      if (error.code === IntlErrorCode.MISSING_MESSAGE) {
        // Missing translations are expected and should only log an error
        console.error(error);
      } else {
        // Other errors indicate a bug in the app and should be reported
        reportToErrorTracking(error);
      }
    },

    getMessageFallback({namespace, key, error}) {
      const path = [namespace, key].filter((part) => part != null).join('.');

      if (error.code === IntlErrorCode.MISSING_MESSAGE) {
        return path + ' is not yet translated';
      } else {
        return 'Dear developer, please fix this message: ' + path;
      }
    }

    // ...
  };
});
```

Note that `onError` and `getMessageFallback` are not automatically inherited by Client Components. If you want to make this functionality available in Client Components too, you can however create a [client-side provider](#nextintlclientprovider-non-serializable-props) that defines these props.

<Details id="error-handling-fallback">
<summary>How can I use messages from another locale as a fallback?</summary>

The `getMessageFallback` setting is intended to customize the error case for apps which want to treat missing messages as errors.

If you expect missing messages for certain locales, you can consider merging messages e.g. from the default locale with the ones for the current locale when providing [messages](/docs/usage/configuration#messages).

**Learn more:**

<CourseVideoBanner
  className="mt-2"
  href="https://learn.next-intl.dev/chapters/04-adding-locales/01-messages"
  title="Providing messages"
/>

</Details>

</Tabs.Tab>
<Tabs.Tab>

```tsx
import {NextIntlClientProvider, IntlErrorCode} from 'next-intl';

function onError(error) {
  if (error.code === IntlErrorCode.MISSING_MESSAGE) {
    // Missing translations are expected and should only log an error
    console.error(error);
  } else {
    // Other errors indicate a bug in the app and should be reported
    reportToErrorTracking(error);
  }
}

function getMessageFallback({namespace, key, error}) {
  const path = [namespace, key].filter((part) => part != null).join('.');

  if (error.code === IntlErrorCode.MISSING_MESSAGE) {
    return path + ' is not yet translated';
  } else {
    return 'Dear developer, please fix this message: ' + path;
  }
}

<NextIntlClientProvider
  onError={onError}
  getMessageFallback={getMessageFallback}
>
  ...
</NextIntlClientProvider>;
```

</Tabs.Tab>
</Tabs>
